package com.vrs.common.manager;

import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.scripting.support.ResourceScriptSource;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author dam
 * @create 2024/12/1 11:43
 */
public class LuaScriptManager {

    // 使用ConcurrentHashMap存储已加载的脚本
    private static final Map<String, RedisScript<?>> SCRIPTS = new ConcurrentHashMap<>();

    // 静态初始化块，预加载所有常用脚本
    static {
        loadScript(LuaScriptNameConstant.INVENTORY_UPDATE, "lua/inventory_update.lua", Long.class);
        loadScript(LuaScriptNameConstant.FREE_COURT_INDEX_ALLOCATE, "lua/free_court_index_allocate.lua", Long.class);
    }

    // 私有构造函数，防止外部实例化
    private LuaScriptManager() {
        throw new UnsupportedOperationException("This is a utility class and cannot be instantiated.");
    }

    /**
     * 加载Lua脚本，并确保每个脚本只加载一次。
     *
     * @param name       脚本的唯一标识符
     * @param path       Lua脚本文件的路径
     * @param resultType 脚本返回值的类型
     * @param <T>        泛型类型
     * @return 加载的RedisScript对象
     */
    public static <T> RedisScript<T> loadScript(String name, String path, Class<T> resultType) {
        DefaultRedisScript<T> script = new DefaultRedisScript<>();
        Resource resource = new ClassPathResource(path);
        script.setScriptSource(new ResourceScriptSource(resource));
        script.setResultType(resultType);
        SCRIPTS.put(name, script);
        return script;
    }

    /**
     * 获取已加载的Lua脚本。
     *
     * @param name 脚本的唯一标识符
     * @param <T>  泛型类型
     * @return 已加载的RedisScript对象
     */
    public static <T> RedisScript<T> getScript(String name) {
        @SuppressWarnings("unchecked")
        RedisScript<T> script = (RedisScript<T>) SCRIPTS.get(name);
        if (script == null) {
            throw new IllegalArgumentException("Script not found: " + name);
        }
        return script;
    }
}
